%%--- coding:utf-8 ---
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% File Name: mc_manager
%%% Created on : 2024/9/3 8:33
%%% @author Gaylen 252323463@qq.com
%%% @copyright (C) 2024, freedom
%%% @doc
%%%     管理进程
%%% @end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

-module(mc_manager).
-behaviour(gen_server).
-author("Gaylen").
-include("mongodb_driver.hrl").

%% API
-export([start_link/2, close/1, get_pid/1]).
-export([
    init/1,
    handle_call/3,
    handle_cast/2,
    handle_info/2,
    terminate/2,
    code_change/3,
    async_apply/3,
    async_apply/5,
    sync_apply/3
]).

start_link(ManageRegName, Options) ->
    gen_server:start_link({local, ManageRegName}, ?MODULE, [Options], []).

close(ManageRegNameOrPid) ->
    Pid = get_pid(ManageRegNameOrPid),
    gen_server:cast(Pid, halt).

get_pid(ManageRegNameOrPid) ->
    if
        is_pid(ManageRegNameOrPid) -> ManageRegNameOrPid;
        true -> whereis(ManageRegNameOrPid)
    end.

init([Options]) ->
    State = mc_manager_logic:init(Options),
    {ok, State}.

handle_call({sync_apply, Func, Args}, _From, State) ->
    {ok, NewState, Result} = erlang:apply(Func, [State | Args]),
    {reply, Result, NewState};
handle_call(_Info, _From, State) ->
    {reply, ok, State}.

handle_cast({async_apply, Func, Args, FromPid, ReplyFunc, ReplyArgs}, State) ->
    {ok, NewState, Result} = erlang:apply(Func, [State | Args]),
    if
        ReplyFunc =/= undefined andalso ReplyArgs =/= undefined ->
            FromPid ! {async_apply_reply, ReplyFunc, [Result | ReplyArgs]};
        true ->
            skip
    end,
    {noreply, NewState};
handle_cast(halt, State) ->
    {stop, normal, State};
handle_cast(_Info, State) ->
    {noreply, State}.

handle_info({worker_check}, State) ->
    WorkerTimerRef = erlang:send_after(60000, self(), {worker_check}),
    NewState = mc_manager_logic:worker_process_check(State#mongo_manager_state{worker_timer = WorkerTimerRef}),
    {noreply, NewState};
handle_info({free_pool_check}, State) ->
    FreePoolTimerRef = erlang:send_after(60000, self(), {free_pool_check}),
    NewState = mc_manager_logic:pool_process_check(State#mongo_manager_state{free_pool_timer = FreePoolTimerRef}),
    {noreply, NewState};
handle_info({'EXIT', ExitPid, _Reason}, State) ->
    NewState = mc_manager_logic:exit_process(ExitPid, State),
    {noreply, NewState};
handle_info(_Info, State) ->
    {noreply, State}.

terminate(Reason, State) ->
    mc_manager_logic:stop(State),
    {stop, Reason, State}.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

async_apply(ManageRegName, Func, Args) ->
    async_apply(ManageRegName, Func, Args, undefined, undefined).
async_apply(ManageRegName, Func, Args, ReplyFunc, ReplyArgs) ->
    Pid = get_pid(ManageRegName),
    gen_server:cast(Pid, {async_apply, Func, Args, self(), ReplyFunc, ReplyArgs}).

sync_apply(ManageRegName, Func, Args) ->
    Pid = get_pid(ManageRegName),
    gen_server:call(Pid, {sync_apply, Func, Args}).
